﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BD.LogHelper;
using Com.Hikvision.Wrapper.Core;
using Com.Hikvision.Wrapper.Core.Domain.EntranceControl;

namespace Com.Hikvision.Wrapper.Service.EntranceControl.RemoteEntranceControl
{
    public class AlertManage : IDisposable
    {
        private static readonly Core.Infrastructure coreInfrastructure = new Infrastructure();
        private CHCNetSDK.MSGCallBack_V31 m_falarmData_V31 = null;
        //private int _iUserId = -1, _alertHandle = -1;
        private int[] _handleList=new int[200];
        private List<int> _listUser = new List<int>();
        private static readonly object _lock = new object();

        /// <summary>
        /// 接收到刷卡数据后处理方法
        /// </summary>
        public Action<UserRecord> RecordReceivedHandle { get; set; }

        public AlertManage()
        {
            for (int i = 0; i < _handleList.Length; i++)
            {
                _handleList[i] = -1;
            }

            //初始化
            coreInfrastructure.NetDvrInit();

            ////设置透传报警信息类型
            //CHCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struLocalCfg = new CHCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
            //struLocalCfg.byAlarmJsonPictureSeparate = 1;//控制JSON透传报警数据和图片是否分离，0-不分离(COMM_VCA_ALARM返回)，1-分离（分离后走COMM_ISAPI_ALARM回调返回）

            //Int32 nSize = Marshal.SizeOf(struLocalCfg);
            //IntPtr ptrLocalCfg = Marshal.AllocHGlobal(nSize);
            //Marshal.StructureToPtr(struLocalCfg, ptrLocalCfg, false);

            //if (!CHCNetSDK.NET_DVR_SetSDKLocalCfg(17, ptrLocalCfg))  //NET_DVR_LOCAL_CFG_TYPE_GENERAL
            //{
            //    var iLastErr = CHCNetSDK.NET_DVR_GetLastError();
            //    Log4.ErrorLog($"【NET_DVR_SetSDKLocalCfg】设置透传报警信息类型,错误代码【{iLastErr}】");
            //}
            //Marshal.FreeHGlobal(ptrLocalCfg);

            ////设置异常消息回调函数
            //var m_fExceptionCB = new CHCNetSDK.EXCEPYIONCALLBACK(cbExceptionCB);
            //CHCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, IntPtr.Zero, m_fExceptionCB, IntPtr.Zero);

            AlertCallBack();
        }

        public void cbExceptionCB(uint dwType, int lUserID, int lHandle, IntPtr pUser)
        {
            //异常消息信息类型
            string stringAlarm = "异常消息回调，信息类型：0x" + Convert.ToString(dwType, 16) + ", lUserID:" + lUserID + ", lHandle:" + lHandle;

            Log4.ErrorLog(stringAlarm);
        }

        [HandleProcessCorruptedStateExceptions]
        public bool DeviceArming(
            out string message,
            string deviceIpAddr,
            int devicePort,
            string user = "admin",
            string password = "")
        {
            message = string.Empty;
            uint errCode = 0;

            try
            {
                //AlertCallBack();

                #region login

                CHCNetSDK.NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = new CHCNetSDK.NET_DVR_DEVICEINFO_V40();

                //登录设备 Login the device
                var iUserId = coreInfrastructure.NetDvrLoginV40(deviceIpAddr, devicePort, user, password,
                    ref struDeviceInfoV40);

                if (iUserId < 0)
                {
                    errCode = coreInfrastructure.NetDvrGetLastError();
                    message = "NET_DVR_Login_V40 failed, error code= " + errCode; //登录失败，输出错误号
                    // coreInfrastructure.NetDvrCleanUp();
                    return false;
                }

                _listUser.Add(iUserId);

                #endregion

                Thread.Sleep(PreSettings.durationCallback);

                CHCNetSDK.NET_DVR_SETUPALARM_PARAM struAlarmParam = new CHCNetSDK.NET_DVR_SETUPALARM_PARAM();
                struAlarmParam.dwSize = (uint) Marshal.SizeOf(struAlarmParam);
                struAlarmParam.byLevel = 1; //0- 一级布防,1- 二级布防
                struAlarmParam.byAlarmInfoType = 1; //智能交通设备有效，新报警信息类型
                struAlarmParam.byFaceAlarmDetection = 1; //1-人脸侦测


                _handleList[iUserId] = CHCNetSDK.NET_DVR_SetupAlarmChan_V41(iUserId, ref struAlarmParam);
                if (_handleList[iUserId] < 0)
                {
                    uint errorCode = CHCNetSDK.NET_DVR_GetLastError();
                    Log4.ErrorLog($"设备布防失败,errorCode【{errorCode}】");
                    // Dispose();
                    return false;
                }

                return errCode == 0;
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return errCode == 0;
            }
        }

        [HandleProcessCorruptedStateExceptions]
        public void AlertClose()
        {
            try
            {
                _listUser.ForEach(id =>
                {
                    if (_handleList[id] >= 0)
                    {
                        if (!CHCNetSDK.NET_DVR_CloseAlarmChan_V30(_handleList[id]))
                        {
                            var iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                            Log4.ErrorLog($"撤防失败, errCode: { iLastErr }");
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                Log4.ErrorLog($"撤防失败, method: AlertClose, errCode: { ex.Message }");
            }
        }

        /// <summary>
        /// 布防回调函数设置
        /// </summary>
        [HandleProcessCorruptedStateExceptions]
        public void AlertCallBack()
        {
            //设置报警回调函数
            try
            {
                m_falarmData_V31 = new CHCNetSDK.MSGCallBack_V31(MsgCallback_V31);

                CHCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(m_falarmData_V31, IntPtr.Zero);
            }
            catch(Exception ex)
            {
                Log4.ErrorLog($"回调函数出错, method: AlertCallBack, error: { ex.Message }");
            }
        }

        [HandleProcessCorruptedStateExceptions]
        public bool MsgCallback_V31(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            try
            {
                lock (_lock)
                {
                    //通过lCommand来判断接收到的报警信息类型，不同的lCommand对应不同的pAlarmInfo内容
                    AlarmMessageHandle(lCommand, ref pAlarmer, pAlarmInfo, dwBufLen, pUser);

                    return true; //回调函数需要有返回，表示正常接收到数据
                }
            }
            catch (Exception ex)
            {
                Log4.ErrorLog($"接收刷卡记录出错, method: MsgCallback_V31, error: { ex.Message }");
                return false;
            }
        }

        [HandleProcessCorruptedStateExceptions]
        public void AlarmMessageHandle(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            //通过lCommand来判断接收到的报警信息类型，不同的lCommand对应不同的pAlarmInfo内容
            switch (lCommand)
            {
                //case CHCNetSDK.COMM_ALARM: //(DS-8000老设备)移动侦测、视频丢失、遮挡、IO信号量等报警信息
                //    //ProcessCommAlarm(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ALARM_V30://移动侦测、视频丢失、遮挡、IO信号量等报警信息
                //    //ProcessCommAlarm_V30(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ALARM_RULE://进出区域、入侵、徘徊、人员聚集等行为分析报警信息
                //    //ProcessCommAlarm_RULE(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_UPLOAD_PLATE_RESULT://交通抓拍结果上传(老报警信息类型)
                //    //ProcessCommAlarm_Plate(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ITS_PLATE_RESULT://交通抓拍结果上传(新报警信息类型)
                //    //ProcessCommAlarm_ITSPlate(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ALARM_TPS_REAL_TIME://交通抓拍结果上传(新报警信息类型)
                //    //ProcessCommAlarm_TPSRealInfo(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ALARM_TPS_STATISTICS://交通抓拍结果上传(新报警信息类型)
                //    //ProcessCommAlarm_TPSStatInfo(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ALARM_PDC://客流量统计报警信息
                //    //ProcessCommAlarm_PDC(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ITS_PARK_VEHICLE://客流量统计报警信息
                //    //ProcessCommAlarm_PARK(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_DIAGNOSIS_UPLOAD://VQD报警信息
                //    //ProcessCommAlarm_VQD(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_UPLOAD_FACESNAP_RESULT://人脸抓拍结果信息
                //    //ProcessCommAlarm_FaceSnap(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_SNAP_MATCH_ALARM://人脸比对结果信息
                //    //ProcessCommAlarm_FaceMatch(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ALARM_FACE_DETECTION://人脸侦测报警信息
                //    //ProcessCommAlarm_FaceDetect(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ALARMHOST_CID_ALARM://报警主机CID报警上传
                //    //ProcessCommAlarm_CIDAlarm(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_UPLOAD_VIDEO_INTERCOM_EVENT://可视对讲事件记录信息
                //    //ProcessCommAlarm_InterComEvent(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                case CHCNetSDK.COMM_ALARM_ACS://门禁主机报警上传
                    ProcessCommAlarm_AcsAlarm(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                    break;
                //case CHCNetSDK.COMM_ID_INFO_ALARM://身份证刷卡信息上传
                //    //ProcessCommAlarm_IDInfoAlarm(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_UPLOAD_AIOP_VIDEO://设备支持AI开放平台接入，上传视频检测数据
                //    //ProcessCommAlarm_AIOPVideo(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_UPLOAD_AIOP_PICTURE://设备支持AI开放平台接入，上传图片检测数据
                //    //ProcessCommAlarm_AIOPPicture(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                //case CHCNetSDK.COMM_ISAPI_ALARM://ISAPI报警信息上传
                //    //ProcessCommAlarm_ISAPIAlarm(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
                //    break;
                default:
                    break;
            }
        }

        [HandleProcessCorruptedStateExceptions]
        private void ProcessCommAlarm_AcsAlarm(ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen,
            IntPtr pUser)
        {
            CHCNetSDK.NET_DVR_ACS_ALARM_INFO struAcsAlarm = new CHCNetSDK.NET_DVR_ACS_ALARM_INFO();
            uint dwSize = (uint)Marshal.SizeOf(struAcsAlarm);
            try
            {
                if (pAlarmInfo == IntPtr.Zero) return;

                struAcsAlarm =
                    (CHCNetSDK.NET_DVR_ACS_ALARM_INFO) Marshal.PtrToStructure(pAlarmInfo,
                        typeof(CHCNetSDK.NET_DVR_ACS_ALARM_INFO));
            }
            catch (ArgumentNullException ex)
            {
                Log4.ErrorLog($"ProcessCommAlarm_AcsAlarm: {ex.Message}");
                return;
            }
            string stringAlarm = "门禁主机报警信息，dwMajor：" + struAcsAlarm.dwMajor + "，dwMinor：" + struAcsAlarm.dwMinor +
                                 "，卡号："
                                 + Encoding.UTF8.GetString(struAcsAlarm.struAcsEventInfo.byCardNo).TrimEnd('\0') +
                                 "，读卡器编号：" +
                                 struAcsAlarm.struAcsEventInfo.dwCardReaderNo + "，报警触发时间：" + struAcsAlarm.struTime.dwYear + ", 工号：" +
                                 struAcsAlarm.struAcsEventInfo.dwEmployeeNo
                                 + ", 刷卡类型：" + struAcsAlarm.struAcsEventInfo.bySwipeCardType + ", 设备名称：" +
                                 Encoding.UTF8.GetString(pAlarmer.sDeviceName) + 
                                 ", IP:" + Encoding.UTF8.GetString(pAlarmer.sDeviceIP).TrimEnd('\0') + ", " + struAcsAlarm.struAcsEventInfo.dwEmployeeNo;

            Log4.InfoLog(stringAlarm);

            var userRecord = new UserRecord();
            //报警设备IP地址
            userRecord.DeviceIp = Encoding.UTF8.GetString(pAlarmer.sDeviceIP).TrimEnd('\0');

            //保存抓拍图片
            if ((struAcsAlarm.dwPicDataLen != 0) && (struAcsAlarm.pPicData != IntPtr.Zero))
            {
                //string str = ".\\picture\\Device_Acs_CapturePic_[" + strIP + "]_lUerID_[" + pAlarmer.lUserID +
                //             "].jpg";
                //var fs = new FileStream(str, FileMode.Create);
                var iLen = (int)struAcsAlarm.dwPicDataLen;
                var by = new byte[iLen];
                Marshal.Copy(struAcsAlarm.pPicData, by, 0, iLen);
                //fs.Write(by, 0, iLen);
                //fs.Close();

                userRecord.FaceImage = by;
            }

            //报警时间：年月日时分秒
            userRecord.AlertTime = new DateTime((int)struAcsAlarm.struTime.dwYear, (int)struAcsAlarm.struTime.dwMonth,
                (int)struAcsAlarm.struTime.dwDay,
                (int)struAcsAlarm.struTime.dwHour, (int)struAcsAlarm.struTime.dwMinute,
                (int)struAcsAlarm.struTime.dwSecond);

            userRecord.Major = (int) struAcsAlarm.dwMajor;

            userRecord.Minor = (int) struAcsAlarm.dwMinor;

            userRecord.CardNo = Encoding.UTF8.GetString(struAcsAlarm.struAcsEventInfo.byCardNo).TrimEnd('\0');

            userRecord.UserId = struAcsAlarm.struAcsEventInfo.dwEmployeeNo == 0 ? 0 : (int)struAcsAlarm.struAcsEventInfo.dwEmployeeNo;

            RecordReceivedHandle?.Invoke(userRecord);

            //string strTimeYear = (struAcsAlarm.struTime.dwYear).ToString();
            //string strTimeMonth = (struAcsAlarm.struTime.dwMonth).ToString("d2");
            //string strTimeDay = (struAcsAlarm.struTime.dwDay).ToString("d2");
            //string strTimeHour = (struAcsAlarm.struTime.dwHour).ToString("d2");
            //string strTimeMinute = (struAcsAlarm.struTime.dwMinute).ToString("d2");
            //string strTimeSecond = (struAcsAlarm.struTime.dwSecond).ToString("d2");
            //string strTime = strTimeYear + "-" + strTimeMonth + "-" + strTimeDay + " " + strTimeHour + ":" + strTimeMinute + ":" + strTimeSecond;
            //string stringAlarm = "门禁主机报警信息，dwMajor：" + struAcsAlarm.dwMajor + "，dwMinor：" + struAcsAlarm.dwMinor +
            //                     "，卡号："
            //                     + Encoding.UTF8.GetString(struAcsAlarm.struAcsEventInfo.byCardNo).TrimEnd('\0') +
            //                     "，读卡器编号：" +
            //                     struAcsAlarm.struAcsEventInfo.dwCardReaderNo + "，报警触发时间：" + strTime + ", 工号：" +
            //                     struAcsAlarm.struAcsEventInfo.dwEmployeeNo
            //                     + ", 刷卡类型：" + struAcsAlarm.struAcsEventInfo.bySwipeCardType + ", 设备名称：" +
            //                     Encoding.UTF8.GetString(pAlarmer.sDeviceName);



            // string stringAlarm = $"门禁主机报警信息，dwMajor：{struAcsAlarm.dwMajor}，dwMinor：{struAcsAlarm.dwMinor}";
            // Log4.WarnLog($"{stringAlarm}");

            //Thread.Sleep(500);
        }

        public void Dispose()
        {
            if (_listUser.Any())
            {
                _listUser.ForEach(id =>
                {
                    //注销用户
                    coreInfrastructure.NetDvrLogout(id);
                });

                AlertClose();
            }

            //释放 SDK 资源
            coreInfrastructure.NetDvrCleanUp();
        }
    }
}
